﻿using System;
using System.Collections.Generic;
using System.Linq;
using Google.Protobuf;

namespace FrameServer.Net
{
    class NetPacket
    {
        private const int buffer_size = 1024;
        private const int max_size = 1024 * 1024 * 5; //5MB
        public byte[] buffer = new byte[buffer_size];
        private byte[] tempBuffer = null;//接受到很大的消息的时候用
        private bool isUsingTempBuf = false;//标识当前tempBuffer有在被使用

        private int _start = 0;
        public int Remain => buffer.Length - _start;
        public int Start => _start;

        public void UnpackMessage(int msgLen, Action<byte, byte[]> OperationRequest)
        {
            //message type: len(4) code(1) data(x)
            //message: <length> 1 username=123|password=123
            _start += msgLen;
            while (true)
            {
                if (_start <= 4)
                {
                    return;
                }

                int totalLen = BitConverter.ToInt32(buffer, 0);//获取前四个字节（记录着当前这一条tcp消息的总长度
                                                               //Console.WriteLine("totalLen: " + totalLen);
                if (_start >= totalLen) // 消息长度小于等于buffer_size，完整的消息，但可能粘包
                {
                    //0-3 length; 4 code; 5-x data
                    int dataLen = totalLen - 5;
                    byte msgId = buffer[4];
                    byte[] data = new byte[dataLen];
                    Array.Copy(buffer, 5, data, 0, dataLen);
                    OperationRequest(msgId, data);

                    Array.Copy(buffer, totalLen, buffer, 0, _start - totalLen);//最前面的消息被处理完了，把后面消息挪到最前面
                    _start -= totalLen;

                    if (isUsingTempBuf)
                    {
                        buffer = new byte[buffer_size];
                        tempBuffer = null;
                        isUsingTempBuf = false;
                    }
                }
                else//这个消息被分割了，是不完整的
                {
                    if (totalLen > buffer_size)//这个消息太大了，比缓冲还大。扩容
                    {
                        tempBuffer = new byte[totalLen];
                        Array.Copy(buffer, tempBuffer, buffer.Length);//将buffer中的数据全部转移到tempBuffer中
                        buffer = tempBuffer;//暂时给buffer扩容，其大小等于消息的大小

                        //将这个标识符置位，目的：当下次接受并处理消息完毕时，复原buffer的大小
                        isUsingTempBuf = true;
                    }
                    break;
                }
            }
        }


        public static byte[] PackMessage(NetMsgID msgId, IMessage message)
        {
            byte opCode_byte = (byte)msgId;
            byte[] respCode_bytes = new byte[1] { opCode_byte };
            byte[] parameter_bytes = Serialize(message);
            byte[] data = respCode_bytes.Concat(parameter_bytes).ToArray();

            int totalLen = data.Length + 4;
            byte[] len_bytes = BitConverter.GetBytes(totalLen);
            byte[] res = len_bytes.Concat(data).ToArray();
            return res;
        }

        public static byte[] Serialize(IMessage t)
        {
            return t.ToByteArray();
        }

        public static T Deserialize<T>(byte[] bytes) where T : IMessage<T>, new()
        {
            return new MessageParser<T>(() => new T()).ParseFrom(bytes);
        }

        public static string DictionaryToString(Dictionary<byte, object> dict)
        {
            string str = "";
            foreach (byte key in dict.Keys)
            {
                str += key + "=" + dict[key];
                str += "|";
            }
            str = str.Substring(0, str.Length - 1);
            return str;
        }
        
        public static string DictionaryToString(Dictionary<string, object> dict)
        {
            string str = "";
            foreach (string key in dict.Keys)
            {
                str += key + "=" + dict[key];
                str += "|";
            }
            str = str.Substring(0, str.Length - 1);
            return str;
        }

        public static Dictionary<string, object> StringToDictionary(string value)
        {
            if (value.Length < 1)
            {
                return null;
            }
            Dictionary<string, object> dic = new Dictionary<string, object>();

            string[] dicStrs = value.Split('|');
            foreach (string str in dicStrs)
            {
                string[] strs = str.Split('=');
                dic.Add(strs[0], strs[1]);
            }
            return dic;
        }
    }
}
